package org.flashamaphone.voices
{
	import flash.utils.ByteArray;
	
	import org.flashamaphone.buffer.SoundConstants;
	import org.flashamaphone.voices.waveformFactories.IWaveFactory;
	import org.flashamaphone.voices.waveformFactories.SineWaveFactory;
	
	/** 
	 * base voice, default to sine wave - pass in a factory for a different voice
	 */
	public class Voice implements IVoice
	{
		public static const MULTIPLIER:Number = (2*Math.PI)/SoundConstants.SAMPLING_RATE;
		
		/** volume */
		protected var _volume:Number = 1;
		
		/** simple voice configuration */
		protected var _config:VoiceConfig;
		
		/** last cycle read */
		protected var _lastCycle:int = 0;
		
		/** 
		 * constructor
		 */
		public function Voice(config:VoiceConfig = null, volume:Number = 1){
			if (config) {
				_config = config;
			} else {
				_config = new VoiceConfig();
			}
			_volume = volume;
		}
		
		/**
		 * get volume
		 * 
		 * @return volume
		 */
		public function get volume():Number {
			return _volume;
		}
		
		/**
		 * set volume
		 * 
		 * @param volume
		 */
		public function set volume(value:Number):void {
			_volume = value;
		}
		
		/**
		 * get press bytes
		 * 
		 * @param frequency
		 * @param duration (milliseconds)
		 * @return sound byteArray
		 */
		public function press(freq:Number, milliseconds:Number, wave:IWaveFactory = null):ByteArray {
			if (!wave) {
				wave = _config.pressWave;
			}
			var returnBytes:ByteArray = new ByteArray();
			var numSamples:int = (milliseconds * SoundConstants.SAMPLING_RATE_MILLISECONDS);
			returnBytes = wave.cycle(freq, numSamples, _lastCycle, _volume, _config.pressEnvelope);
			_lastCycle = wave.lastSampleIndex +1;
			return returnBytes;
		}
		
		/**
		 * get hold bytes
		 * 
		 * @param frequency
		 * @param duration (milliseconds)
		 * @param if is streaming
		 * 
		 * @return sound byteArray
		 */
		public function hold(freq:Number, milliseconds:Number, streaming:Boolean = false, wave:IWaveFactory = null):ByteArray {
			if (!wave) {
				wave = _config.holdWave;
			}
			var returnBytes:ByteArray = new ByteArray();
			var numSamples:int = (milliseconds * SoundConstants.SAMPLING_RATE_MILLISECONDS);
			returnBytes = wave.cycle(freq, numSamples, _lastCycle, _volume, _config.holdEnvelope);
			_lastCycle = wave.lastSampleIndex +1;
			return returnBytes;
		}
		
		/**
		 * get unpress bytes
		 * 
		 * @param frequency
		 * @param duration (milliseconds)
		 * @return sound byteArray
		 */
		public function unpress(freq:Number, milliseconds:Number, wave:IWaveFactory = null):ByteArray {
			if (!wave) {
				wave = _config.unpressWave;
			}
			var returnBytes:ByteArray = new ByteArray();
			var numSamples:int = (milliseconds * SoundConstants.SAMPLING_RATE_MILLISECONDS);
			returnBytes = wave.cycle(freq, numSamples, _lastCycle, _volume, _config.unpressEnvelope);
			_lastCycle = wave.lastSampleIndex +1;
			return returnBytes;
		}
		
		/** 
		 * get press duration
		 * 
		 * @return duration
		 */
		public function get pressDuration():int {
			return _config.pressDuration;
		}

		/** 
		 * get unpress duration
		 * 
		 * @return duration
		 */
		public function get unpressDuration():int {
			return _config.unpressDuration;
		}
		
		/** 
		 * get hold duration
		 * 
		 * @return duration
		 */
		public function get holdDuration():int {
			return _config.holdDuration;
		}
		
	}
}